#include "mpi.h"
#include "My_Math.h"

#include <fstream.h>


#define GTAG 99
#define Operand_TAG 66
#define RESULT_TAG 55
#define MASTER 0
#define SLAVE1 1


int commSize;
int commRank;
char processorName[64];


void CMPI_Initialise(int argc, char * argv[])
{	
	int  namelen; // temporary variable
	MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&commSize);
    MPI_Comm_rank(MPI_COMM_WORLD,&commRank);
    MPI_Get_processor_name(processorName,&namelen);		
}
/******************************************************************************/
								//Destructor
void CMPI_Finalise()
{
	cout << "\n MPI Finalised:"<<flush;
	MPI_Finalize();
}
/******************************************************************************/
// 0 --> calculation failed
// 1 --> calculation succeeded
int MasterWork()
{
	// This master thread asks the slave # 1 to computes f(x,y) = x^y + 2*x



	cout << "\n MPI Initialised Master:" 
		 << "\n Machine Name: " << processorName
		 << "\n Machine Rank: " << commRank
		 << "\n Comm Size   : " << commSize 
		 << "\n ================================" << flush;


	int x=3, y=2, result=0;
	MPI_Status status;

	// sending the operands x, y to slave # 1
	MPI_Send(&x, 1, MPI_INT, SLAVE1, Operand_TAG, MPI_COMM_WORLD);
	MPI_Send(&y, 1, MPI_INT, SLAVE1, Operand_TAG, MPI_COMM_WORLD);

	//cout << "\n Data sent to slave 1 " << x << " " << y << flush;

	// start receiving the result from Slave # 1
	MPI_Recv(&result, 1, MPI_INT, SLAVE1, RESULT_TAG, MPI_COMM_WORLD, &status);


	cout << "\n Master received f(" << x << " , " << y << ") = "<< result << flush;

	return 1;
}
/******************************************************************************/
void SlaveWork()
{
	// This slave thread computes f(x,y) = x^y + 2*x

	cout << "\n MPI Initialised Slave 1:" 
	 	 << "\n Machine Name: " << processorName
	 	 << "\n Machine Rank: " << commRank
	 	 << "\n Comm Size   : " << commSize
		 << "\n ================================" << flush;

	int x=0, y=0, result;

	MPI_Status status;

	// start receiving values for x and y from master	
	MPI_Recv(&x, 1, MPI_INT, MASTER, Operand_TAG, MPI_COMM_WORLD, &status);
	MPI_Recv(&y, 1, MPI_INT, MASTER, Operand_TAG, MPI_COMM_WORLD, &status);

	//cout << "\n Data received from server " << x << " " << y << flush;

	// compute the function f(x,y) = x^y + 2*x
	result = CMy_Math_Base::myPow(x, y) + 2 * x;

	// sending the result back to master
	MPI_Send(&result, 1, MPI_INT, MASTER, RESULT_TAG, MPI_COMM_WORLD);

	//cout << "\n Result sent to server " << result << flush;
}
/******************************************************************************/
int main(int argc,char *argv[])
{
	CMPI_Initialise(argc, argv);

	int opCode=-1, slaveID=1;
	//double startTime_MPI=0.0, endTime_MPI;	

	if(commRank != 0)
	{
		SlaveWork();
	}

	if(commRank == 0) // I am MASTER	
	{		
		MasterWork();
	}

	CMPI_Finalise();
	cout << flush;
	return 1;
}